using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;

//**********************************************************************
//NOTE:  CHANGED 11-11-08 BECAUSE MICROSOFT.SHAREPOINT.WEBPARTPAGES 
//CAUSED OTHER CUSTOM WEB PARTS BASED ON ASP.NET WEBPARTS TO
//THROW AN ERROR WHEN CASTING TO TYPE WEBPART DURING AN ADD OPERATION
//WOULD NEED TO ADD SOME MORE CODE TO FIGURE OUT WHICH CLASS A PART IS
//BASED ON AND DO THE APPROPRIATE CAST.  FOR NOW CHANGING THE USING
//STATEMENT SO IT WILL WORK WITH THE COMMON CASE CUSTOM WEB PARTS

//using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.WebControls.WebParts;
//***********************************************************************

using System.Xml;
using System.Xml.Serialization;
using System.Xml.Schema;
using System.Diagnostics;
//using Microsoft.SharePoint.Portal.WebControls;
using System.Collections;
using System.Reflection;
using System.ComponentModel;
using System.IO;
using Microsoft.Office.Server.ActivityFeed;
using eGov.SharePoint.MyPeeps.Properties;
using Microsoft.Office.Server.UserProfiles;
using System.Security.Principal;
using eGov.SharePoint.MyPeeps.EventReceivers;

namespace eGov.SharePoint.MyPeeps.WebControls
{
    [XmlRoot("eGov.SharePoint.MyPeeps.WebControls")]
    public class PartCheck : WebControl
    {
        //constants for property simple property setter value tag replacements
        public const string PSV_DOMAIN = "[DOMAIN]";
        public const string PSV_ACCOUNTNAME = "[ACCOUNTNAME]";
        public const string PSV_MACHINE = "[MACHINE]";
        public const string PSV_LOGIN = "[LOGIN]";
        string KEY_CHK = Properties.Settings.Default.PartCheckKey;

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            //generic dictionary to store the list of webparts we're going to work 
            //with and what we'll do with each; Steve likes generics!  :-)
            Dictionary<string, WebPartAction> wpList = null;
            //web part action class to store info about web parts that we're changing
            WebPartAction wpa = null;
            //webpart class that will be used in the action class
            WebPart xWp = null;
            //assembly we'll use to load web parts we are adding
            Assembly wpAsm = null;
            //serializer to convert the xml file into objects
            XmlSerializer slz = null;

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {

                if (SPContext.Current == null || SPContext.Current.Site == null) return;

                Guid SPSiteGuid = SPContext.Current.Site.ID;

                using (SPSite site = new SPSite(SPSiteGuid))
                {
                    SPWeb curWeb = site.OpenWeb();

                    //get the current web; not using "using" because we don't want to kill the web context for other controls that need it
                    //SPWeb curWeb = SPContext.Current.Web;
                    try
                    {
                        //Remove query string parameters from pageName
                        string absoluteUri = HttpContext.Current.Request.Url.AbsoluteUri;
                        if (absoluteUri.IndexOf("?") > -1)
                            absoluteUri = absoluteUri.Split(new char[] { '?' })[0];

                        //look for the page so we can mess with the web parts
                        string pageName = Path.GetFileNameWithoutExtension(absoluteUri);

                        SPFile thePage = null;
                        if (SPContext.Current.File != null)
                            thePage = curWeb.GetFile(SPContext.Current.File.Url);
                        else
                            thePage = curWeb.RootFolder.Files[string.Format("{0}.aspx", pageName)];

                        //look to see if our code has already run on the page
                        if (thePage.Properties[KEY_CHK] == null)
                            thePage.Properties.Add(KEY_CHK, "0");
                        if (thePage.Properties[KEY_CHK].ToString() != "2")
                        {
                            curWeb.AllowUnsafeUpdates = true;

                            ////Register the Custom Activity stream settings
                            //RegisterActivityStreamSettings();

                            if (thePage != null)
                            {
                                XmlDocument xDoc = new XmlDocument();
                                SPFile file = curWeb.Files[string.Format("{0}.xml", pageName)];
                                if (file != null)
                                {
                                    #region Read XML File that defines the page webpart changes

                                    //now that we have the file, read it into an xml document
                                    xDoc.Load(file.OpenBinaryStream());
                                    //xDoc.Load(xItems[0].File.OpenBinaryStream());

                                    //create a hashtable to store our web parts
                                    wpList = new Dictionary<string, WebPartAction>();

                                    //create a new serializer
                                    slz = new XmlSerializer(typeof(WebPartAction));

                                    //enumerate through the child nodes
                                    foreach (XmlNode xNode in xDoc.FirstChild.ChildNodes)
                                    {
                                        try
                                        {
                                            //try serializing each one
                                            wpa = slz.Deserialize(new System.IO.StringReader(xNode.OuterXml)) as
                                                WebPartAction;
                                        }
                                        catch (Exception srlzEx)
                                        {
                                            //some error logging here about invalid xml file
                                            UpdateLog("Error serializing DeafultPageWebpartChanges.xml file: " + srlzEx.Message, EventLogEntryType.Error);

                                            //set our reference to null so we don't try and do something with a version that was successfully serialized previously
                                            wpa = null;
                                        }

                                        //make sure we serialized, and also make sure this is an Add
                                        if (wpa != null)
                                        {
                                            switch (wpa.Action)
                                            {
                                                case WebPartAction.ActionType.Add:

                                                    //now try loading the assembly
                                                    try
                                                    {
                                                        wpAsm = Assembly.Load(wpa.assemblyName);
                                                    }
                                                    catch (Exception asmEx)
                                                    {
                                                        //some error logging here about invalid assembly name
                                                        UpdateLog("Error loading assembly name " + wpa.assemblyName +
                                                            ": " + asmEx.Message, EventLogEntryType.Error);

                                                        //set our reference to null so we don't try and do something with
                                                        //a version that was successfully loaded previously
                                                        wpAsm = null;
                                                    }

                                                    if (wpAsm != null)
                                                    {
                                                        //try creating an instance of the class
                                                        try
                                                        {
                                                            xWp = (WebPart)wpAsm.CreateInstance(wpa.className);
                                                        }
                                                        catch (Exception instEx)
                                                        {
                                                            //some error logging here about invalid class name
                                                            UpdateLog("Error creating instance of class " + wpa.className +
                                                                ": " + instEx.Message, EventLogEntryType.Error);
                                                            xWp = null;
                                                        }

                                                        //plug it into our class
                                                        if (xWp != null)
                                                        {
                                                            //enumerate and add properties to part
                                                            SetWebPartProperties(wpa, xWp);

                                                            //add part to class
                                                            wpa.wp = xWp;
                                                        }
                                                    }

                                                    //add it to the hashtable
                                                    wpList.Add(Guid.NewGuid().ToString(), wpa);
                                                    break;
                                                default:
                                                    //for delete, move or SetProperties we want to capture 
                                                    //the type name and plug it into the hash array
                                                    wpList.Add(wpa.typeName, wpa);
                                                    break;
                                            }
                                        }
                                    }
                                    #endregion

                                    Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager theMan = thePage.GetLimitedWebPartManager(System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared);
                                    foreach (WebPart wp in theMan.WebParts)
                                    {
                                        //check each web part to see if matches our typeName
                                        if (wpList.ContainsKey(wp.GetType().ToString()))
                                            wpList[wp.GetType().ToString()].wp = wp;
                                    }

                                    #region Process Page/Webpart Actions (Delete, Move, Add or Set properties)
                                    //now enumerate items in hash; can't do it in WebPart collection 
                                    //on SPLimitedWebPartManager or it fails
                                    foreach (string key in wpList.Keys)
                                    {
                                        wpa = wpList[key];

                                        switch (wpa.Action)
                                        {
                                            case WebPartAction.ActionType.Delete:
                                                theMan.DeleteWebPart(wpa.wp);
                                                break;
                                            case WebPartAction.ActionType.Move:
                                                theMan.MoveWebPart(wpa.wp, wpa.zoneID, int.Parse(wpa.zoneIndex));
                                                theMan.SaveChanges(wpa.wp);
                                                break;
                                            case WebPartAction.ActionType.Add:
                                                bool exists = false;
                                                foreach (WebPart wpart in theMan.WebParts)
                                                {
                                                    if (wpart.DisplayTitle == wpa.wp.DisplayTitle)
                                                    {
                                                        //Webparts already added, Mark page to skip subsequent execution of this code.
                                                        exists = true;
                                                        thePage.Properties[KEY_CHK] = "2";
                                                        thePage.Update();
                                                    }
                                                }

                                                if (!exists)
                                                    theMan.AddWebPart(wpa.wp, wpa.zoneID, int.Parse(wpa.zoneIndex));

                                                break;
                                            case WebPartAction.ActionType.SetProperties:
                                                SetWebPartProperties(wpa, wpa.wp);
                                                theMan.SaveChanges(wpa.wp);
                                                break;
                                        }
                                        //if (breakOut)
                                        //    break;
                                    }
                                    #endregion

                                    //add our key to the property bag so we don't run our provisioning code again on this page
                                    //Had to do a double check procedure hence setting the value to 1 then 2; 
                                    //Bug where the code didn't register the changes correctly from the first time due to thread abort
                                    //It is working fine for the time being with this resolution
                                    if (thePage.Properties[KEY_CHK].ToString() == "0")
                                        thePage.Properties[KEY_CHK] = "1";
                                    else if (thePage.Properties[KEY_CHK].ToString() == "1")
                                        thePage.Properties[KEY_CHK] = "2";
                                    else
                                        thePage.Properties[KEY_CHK] = "2";

                                    if (thePage.Name.ToLower().IndexOf("mypeeps.aspx") > -1)
                                        EnsureSharedListsFeedSettings(curWeb);

                                    thePage.Update();
                                    curWeb.Update();
                                    //curWeb.Properties.Add(KEY_CHK, "true");
                                    //curWeb.Properties.Update();
                                    curWeb.AllowUnsafeUpdates = false;

                                    //force a page refresh to show the page with the updated layout
                                    Context.Response.Redirect(thePage.Url);
                                }
                            }
                        }
                    }
                    catch (System.Threading.ThreadAbortException abortEx)
                    {
                        //we'll throw a thread abort exception on redirect, so we can ignore it, but
                        //record everything else
                    }
                    catch (Exception ex)
                    {
                        UpdateLog("Error checking web parts: " + ex.Message, EventLogEntryType.Error);
                    }
                }
            });
        }

        private void SetWebPartProperties(WebPartAction wpa, WebPart xWp)
        {
            //check to see if there are any properties; if there are zero it won't say
            //zero, it will say null (unlike vb.net)
            if (wpa.Properties == null)
                return;

            //enumerate and add properties to part
            for (int p = 0; p < wpa.Properties.Property.Length; p++)
            {
                try
                {
                    xWp.GetType().GetProperty(wpa.Properties.Property[p].Key).SetValue(xWp,
                        GetPropertySetterValue(wpa.Properties.Property[p].Value), null);
                }
                catch (Exception propEx)
                {
                    //some error logging here about invalid property name
                    UpdateLog("Error setting property value " +
                        wpa.Properties.Property[p].Key + " to " +
                        wpa.Properties.Property[p].Value +
                        ": " + propEx.Message, EventLogEntryType.Error);
                }
            }
        }

        private string GetPropertySetterValue(string Value)
        {
            string ret = Value;

            switch (Value)
            {
                case PSV_ACCOUNTNAME:
                    ret = Environment.UserName;
                    break;
                case PSV_DOMAIN:
                    ret = Environment.UserDomainName;
                    break;
                case PSV_MACHINE:
                    ret = Environment.MachineName;
                    break;
                case PSV_LOGIN:
                    ret = Environment.UserDomainName + "\\" + Environment.UserName;
                    break;
                default:
                    break;
            }

            return ret;
        }

        private void UpdateLog(string Message, EventLogEntryType msgType)
        {
            try
            {
                System.Diagnostics.EventLog.WriteEntry("MySiteCreatePart", Message, msgType);
            }
            catch
            {
                //ignore
            }
        }

        private void EnsureSharedListsFeedSettings(SPWeb currentWeb)
        {
            if (currentWeb == null) return;
            //SPList sharedDocuments = currentWeb.Lists["Shared Documents"];
            //SPList sharedPictures = currentWeb.Lists["Shared Pictures"];
            SPList sharedDocuments = null;
            SPList sharedPictures = null;
            bool flag_DocumentsEnabled = false, flag_PicturessEnabled = false;

            foreach (SPList list in currentWeb.Lists)
            {
                if (list.Title.ToLower() == "shared documents")
                {
                    sharedDocuments = list;
                    continue;
                }
                else if (list.Title.ToLower() == "shared pictures")
                {
                    sharedPictures = list;
                    continue;
                }
            }

            if (sharedDocuments != null)
                flag_DocumentsEnabled = ContentActionFeedEventReceiver.IsEventReceiverAttached(sharedDocuments);

            if (sharedPictures != null)
                flag_PicturessEnabled = ContentActionFeedEventReceiver.IsEventReceiverAttached(sharedPictures);


            if (!flag_DocumentsEnabled) ContentActionFeedEventReceiver.ActivateServiceOnList(sharedDocuments);
            if (!flag_PicturessEnabled) ContentActionFeedEventReceiver.ActivateServiceOnList(sharedPictures);
        }
    }

    ////close the welcome web part
    //if (wp.GetType().Equals(typeof(PersonalWelcomeWebPart)))
    //  hshWp.Add(wp.StorageKey.ToString(),
    //    new WebPartAction(wp, WebPartAction.ActionType.Delete));

    ////move the RSS web part to the bottom
    //if (wp.GetType().Equals(typeof(RSSAggregatorWebPart)))
    //  hshWp.Add(wp.StorageKey.ToString(),
    //    new WebPartAction(wp, WebPartAction.ActionType.Move, "BottomZone", 0));


    public class WebPartAction
    {

        public enum ActionType
        {
            Add,
            Delete,
            Move,
            SetProperties
        }

        [XmlIgnore()]
        public WebPart wp = null;

        [XmlElement(Form = XmlSchemaForm.Unqualified)]
        public string assemblyName = string.Empty;

        [XmlElement(Form = XmlSchemaForm.Unqualified)]
        public string className = string.Empty;

        [XmlElement(Form = XmlSchemaForm.Unqualified)]
        public string zoneID = string.Empty;

        //using a string to greatly simplify potential errors during deserialization
        [XmlElement(Form = XmlSchemaForm.Unqualified)]
        public string zoneIndex = "0";

        [XmlElement(Form = XmlSchemaForm.Unqualified)]
        public string typeName = string.Empty;

        [XmlElement(Form = XmlSchemaForm.Unqualified)]
        public ActionType Action;

        [XmlElement(Form = XmlSchemaForm.Unqualified)]
        public PropertyRoot Properties;

        public WebPartAction()
        {
            //parameter-less constructor needed for serialization
        }

        public WebPartAction(WebPart wp, ActionType Action)
        {
            this.wp = wp;
            this.Action = Action;
        }

        public WebPartAction(WebPart wp, ActionType Action, string zoneID, string zoneIndex)
        {
            this.wp = wp;
            this.Action = Action;
            this.zoneID = zoneID;
            this.zoneIndex = zoneIndex;
        }

        public class PropertyRoot
        {
            [XmlElement(Form = XmlSchemaForm.Unqualified)]
            public OneProperty[] Property;
        }

        public class OneProperty
        {
            [XmlAttribute(Form = XmlSchemaForm.Unqualified)]
            public string Key = string.Empty;

            [XmlAttribute(Form = XmlSchemaForm.Unqualified)]
            public string Value = string.Empty;
        }

    }
}
